package at.donalfonso.ui.group;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Enumeration;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Topic;
import javax.swing.DefaultListModel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import at.donalfonso.kunde.KundeThreadJMS;
import at.donalfonso.model.Bestellung;
import at.donalfonso.model.Gruppe;
import at.donalfonso.model.LieferBestellung;
import at.donalfonso.model.LieferKunde;
import at.donalfonso.utility.JMSUtility;

public class GroupControllerJMS implements MessageListener, WindowListener, ActionListener {

	private ArrayList<Gruppe> groupsQueue = new ArrayList<Gruppe>();

	private GroupView view = null;
	private JMSUtility jmsUtility = null;
	
//	private HashMap<String, GruppeThreadJMS> threads = new HashMap<String, GruppeThreadJMS>();
	private ArrayList<GruppeThreadJMS> threads = new ArrayList<GruppeThreadJMS>();
	
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {

		if (args.length != 0){
			System.out.println("Parameter werden ignoriert.");
		}
		
		GroupControllerJMS controller = new GroupControllerJMS();
		
		controller.run();
	}

	
	/* Der Groupcontroller soll mit beiden Filialen interagieren können und benötigt daher 
	 * keine FilialID als Parameter.
	 */
	public GroupControllerJMS(){
		try {
			//"com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
			UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
			//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (UnsupportedLookAndFeelException e) {

			e.printStackTrace();
		}

		view = new GroupView(this);		
		view.addWindowListener(this);
		view.setTitle("Don Alfonso: GruppenGUI JMS");

		try {
			// Verbindung zum ActiveMQ Server wird hergestellt.
			getJMSUtility().getConnection().start();

		} catch (JMSException e) {
			e.printStackTrace();
		}
	}

	public void run(){
		
		try {
			
			/* Alle GUI relevanten Events aus Filiale 1 werden über das GUI-Topic empfangen. */
			
			Topic guiTopic = getJMSUtility().getTopicGuiUpdate();
			String selector = "Class = '" + Gruppe.class.getSimpleName() + "'";
			MessageConsumer consGui = getJMSUtility().getSession().createConsumer(guiTopic, selector);
			consGui.setMessageListener(this);
			
			selector = "Class = '" + LieferBestellung.class.getSimpleName() + "'";
			consGui = getJMSUtility().getSession().createConsumer(guiTopic, selector);
			consGui.setMessageListener(this);			
			

			/* Für Filiale 2 wird ein eigener Consumer gestartet */
			guiTopic = getJMSUtility().createTopicGuiUpdate(2);
			selector = "Class = '" + Gruppe.class.getSimpleName() + "'";
			consGui = getJMSUtility().getSession().createConsumer(guiTopic, selector);
			consGui.setMessageListener(this);
			
			selector = "Class = '" + LieferBestellung.class.getSimpleName() + "'";
			consGui = getJMSUtility().getSession().createConsumer(guiTopic, selector);
			consGui.setMessageListener(this);
			
			
		} catch (JMSException e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		}		
	}


	public void addGroup(Gruppe group){
		groupsQueue.add(group);
	}

	/**
	 * Schickt die Gruppen in der Queue in den Space. 
	 */
	public void sendGroupsToSpace(){ 

		DefaultListModel<Gruppe> model = view.getGroupQueueModel();
		Enumeration<Gruppe> queue = model.elements();

		while (queue.hasMoreElements()) {
			Gruppe group = queue.nextElement();
			
			if (group instanceof LieferKunde) {
				// Lieferung
				logger.debug("Thread für LieferKunde " + group.getId() +"("+((LieferKunde)group).adresseExistiert()+") wird gestartet.");
				System.out.println("Thread für LieferKunde " + group.getId() +"("+((LieferKunde)group).adresseExistiert()+") wird gestartet.");
				KundeThreadJMS t = new KundeThreadJMS((LieferKunde) group);
				threads.add(t);
				t.start();
				logger.debug("Thread für LieferKunde " + group.getId() + " gestartet.");
				
			} else {
				// Restaurantbesucher
				logger.debug("Thread für Gruppe " + group.getId() + " wird gestartet.");				
				GruppeThreadJMS t = new GruppeThreadJMS(group);
				threads.add(t);
				t.start();
				logger.debug("Thread für Gruppe " + group.getId() + " gestartet.");
			}
		}
/*	sfu 20130610 Anpassung an XVSM-Version
 * dieser Code muss in KundeThreadJMS und KellnerJMS			
				LieferBestellung bestellung = (LieferBestellung) elm;
				
				// Bestellung für BestellungsID lesen.
				Bestellung bestellungObj = getNextBestellung();
				
				bestellung.setBestellungId(bestellungObj.getBestellungId());
				
				System.out.println("Die Bestellungsid: " + bestellungObj.getBestellungId());
				
				// Wenn die Adresse nicht existiert muss auch kein Kunde darauf warten.
				if (bestellung.adresseExistiert()){
					KundeThreadJMS kunde = new KundeThreadJMS(bestellung.getAdresse(), bestellung.getBestellungId());
					kunde.start();
				}
				
				// Die Lieferbestellung wird ohne Zwischenschritt zu die QueueLieferung geschrieben.
				
				try {
					Queue queueLieferung = getJMSUtility().getQueueLieferung();
					MessageProducer producer = getJMSUtility().getSession().createProducer(queueLieferung);
					Message msg = getJMSUtility().getSession().createObjectMessage(bestellung);
					producer.send(msg);
					
					// In die Topic für den Loadbalancer.
					
					// Der Kellner gibt die Bestellung an die Queue BestellungOffen weiter.
					
				} catch (JMSException e) {
					
					e.printStackTrace();
				}
				
				updateGui(bestellung);
				
			}
		}
*/
		// Die Queue wird geleert.
		model.removeAllElements();
	}
	

	public Bestellung getNextBestellung(){
		
		Bestellung bestellung = null;
		
		try{
			
			JMSUtility jmsUt = new JMSUtility(1);
			jmsUt.getConnection().start();
			
			MessageConsumer cons = jmsUt.getSession().createConsumer(jmsUt.getQueueBestellungNeu());
			Message msgBest = cons.receive();
			cons.close();
			
			if (msgBest instanceof ObjectMessage) {
				Serializable s = ((ObjectMessage) msgBest).getObject();
				if (s instanceof Bestellung) {
					bestellung = (Bestellung) s;
					logger.debug("neue Bestellung erfolgreich gelesen: " + bestellung);
				}
			}
			
		} catch (JMSException e) {
			e.printStackTrace();
		}
		
		return bestellung;
	}

	@Override
	public void onMessage(Message message) {
		
		logger.debug("in onMessage()");
		System.out.println("onMsg: "+message);
		
		if (message instanceof ObjectMessage) {
			Serializable s = null;
			
			try {
				s = ((ObjectMessage) message).getObject();
			} catch (JMSException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			if (s instanceof Gruppe) {
				
				Gruppe gruppe = (Gruppe) s;
				logger.debug("Gruppe empfangen: " + gruppe);

				int index = view.getGroupSystemModel().indexOf(gruppe);
				
				if (index < 0)
					view.getGroupSystemModel().addElement(gruppe);
				else
					view.getGroupSystemModel().set(index, gruppe);
				
			}
/*			
			if (s instanceof LieferBestellung){
				LieferBestellung bestellung = (LieferBestellung) s;
				logger.debug("Lieferbestellung erhalten.");
				System.out.println("lieferbest: " + bestellung);
				
				int index = view.getGroupSystemModel().indexOf(bestellung);
				
				if (index < 0)
					view.getGroupSystemModel().addElement(bestellung);
				else
					view.getGroupSystemModel().set(index, bestellung);
			}
*/
		}	
	}

	@Override
	public void windowActivated(WindowEvent arg0) {

	}

	@Override
	public void windowClosed(WindowEvent arg0) {

	}

	@Override
	public void windowClosing(WindowEvent arg0) {
		logger.info("Shutdown der Threads beginnt.");
		for (Thread t: threads) {
			if (t.isAlive())
				t.interrupt();
			try {
				t.join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		logger.info("Shutdown der Threads beendet, Shutdown von JMS beginnt.");
		try {
			getJMSUtility().getSession().close();
		} catch (JMSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		logger.info("Shutdown abgeschlossen.");
	}

	@Override
	public void windowDeactivated(WindowEvent arg0) {

	}

	@Override
	public void windowDeiconified(WindowEvent arg0) {

	}

	@Override
	public void windowIconified(WindowEvent arg0) {

	}

	@Override
	public void windowOpened(WindowEvent arg0) {

	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getActionCommand().equals("Send queue to Space"))
			sendGroupsToSpace();
		//		if (e.getActionCommand().equals("Testdaten schicken"))
		//			test1();
	}

	public JMSUtility getJMSUtility(){
		if (jmsUtility == null){
			
			// Die Filiale spielt hier keine Rolle da GroupControllerJMS nur auf das Topic GuiUpdate reagiert.
			jmsUtility = new JMSUtility(1);
		}
		return jmsUtility;
	}

	/**
	 * Über das Topic "Gui_update" werden Statusänderungen kommuniziert.
	 */
	public void updateGui(Serializable object){
		
		System.out.println("updateGui: " + object);
		logger.debug("Updating Gui.");
		
		try {
			Topic topic = getJMSUtility().getTopicGuiUpdate();
			Message msg = getJMSUtility().getSession().createObjectMessage(object);
			msg.setStringProperty("Class", object.getClass().getSimpleName());
			
			MessageProducer producer = getJMSUtility().getSession().createProducer(topic);
			
			producer.send(msg);
			
			producer.close();
			
		} catch (JMSException e) {
			
			logger.debug("GUI Update failed.");
			
			e.printStackTrace();
		}	
	}
}
